package com.seeyon.ctp.rest.resources;

import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.alibaba.fastjson.JSONObject;
import com.seeyon.apps.lzmzj.kit.HttpKit;
import com.seeyon.apps.lzmzj.kit.StrKit;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.common.exceptions.BusinessException;
import com.seeyon.ctp.common.log.CtpLogFactory;
import com.seeyon.ctp.organization.bo.V3xOrgMember;
import com.seeyon.ctp.organization.manager.OrgManager;
import com.seeyon.ctp.util.UUIDLong;
import org.apache.commons.logging.Log;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Path("jssdk")
@Consumes(MediaType.APPLICATION_JSON)
@Produces({MediaType.APPLICATION_JSON})
public class CustomSSOResources extends BaseResource {

    private static final Log log = CtpLogFactory.getLog(CustomSSOResources.class);
    @Context
    private HttpServletRequest request;

    @Context
    private HttpServletResponse response;

    private OrgManager orgManager = (OrgManager) AppContext.getBean("orgManager");

    /**
     * 获取单点登录认证码
     * 该方法用于通过HTTP GET请求获取单点登录（SSO）的认证码它主要经历了几个步骤：
     * 1. 从请求参数中提取认证码（authCode）。
     * 2. 若认证码非空，使用认证码向指定URL获取访问令牌（accessToken）。
     * 3. 使用获取的访问令牌获取用户信息，特别是用户的电话号码。
     * 4. 根据电话号码获取对应的系统登录名。
     * 5. 最后，使用登录名构造重定向URL，使用户能够完成单点登录流程。
     *
     * @param param 参数映射，目前未使用但保留以备将来扩展
     * @return 响应对象，可能包含错误信息或重定向到登录页面
     */
    @GET
    @Path("acquire/sso/authCode")
    public Response acquireSSOAuthCode(Map<String, Object> param) {
        try {
            // 从请求参数中获取authCode
            String authCode = request.getParameter("authCode");
            log.info("authCode:" + authCode);
            // 初始化电话号码变量
            String phone = "";
            // 如果authCode非空，则继续流程
            if (!"".equals(authCode)) {
                // 构造获取accessToken的URL
                String accessTokenUrl = AppContext.getSystemProperty("tyrzzx.accessTokenUrl");
                String applyId = AppContext.getSystemProperty("tyrzzx.applyId");
                StringBuilder stb = new StringBuilder();
                stb.append(accessTokenUrl).append("?authCode=").append(authCode);
                stb.append("&grant_type=ssoLogin");
                log.info("获取accessToken接口url:" + stb.toString());
                // 构造请求头
                Map<String, Object> headerMap = new HashMap<String, Object>();
                String Authorization = "Basic " + applyId;
                log.info("获取accessToken接口Authorization:" + Authorization);
                headerMap.put("Authorization", Authorization);
                // 发送请求获取accessToken
                String result = HttpKit.post(stb.toString(), headerMap, "");
                log.info("获取accessToken接口返回信息:" + result);
                // 解析响应
                JSONObject jsonObject = JSONObject.parseObject(result);
                String code = StrKit.str(jsonObject.get("code"));
                String accessToken = "";
                // 如果响应码为200，则提取accessToken
                if (code.equals("200")) {
                    accessToken = StrKit.str(jsonObject.getJSONObject("data").get("accessToken"));
                } else {
                    // 否则返回错误信息
                    String msg = StrKit.str(jsonObject.get("msg"));
                    return ok("获取accessToken失败:" + msg);
                }
                // 如果accessToken非空，则尝试获取用户信息
                if (!"".equals(accessToken)) {
                    // 构造获取用户信息的URL
                    String userInfoUrl = AppContext.getSystemProperty("tyrzzx.userInfoUrl");
                    log.info("获取用户信息接口url:" + userInfoUrl);
                    // 构造请求头
                    Map<String, Object> userinfo_headerMap = new HashMap<String, Object>();
                    String userinfo_authorization = "bearer " + accessToken;
                    userinfo_headerMap.put("Authorization", userinfo_authorization);
                    log.info("获取用户信息接口Authorization:" + userinfo_authorization);
                    // 发送请求获取用户信息
                    String userinfo_result = HttpKit.post(userInfoUrl, userinfo_headerMap, "");
                    log.info("获取用户信息接口返回信息:" + userinfo_result);
                    // 解析响应
                    JSONObject userinfo_jsonObject = JSONObject.parseObject(userinfo_result);
                    String userinfo_code = StrKit.str(userinfo_jsonObject.get("code"));
                    String userInfoStr = "";
                    // 如果响应码为200，则提取并解密用户信息
                    if (userinfo_code.equals("200")) {
                        userInfoStr = StrKit.str(userinfo_jsonObject.get("data"));
                        String sm4_key = AppContext.getSystemProperty("sm4.key");
                        SymmetricCrypto sm4 = SmUtil.sm4(sm4_key.getBytes());
                        byte[] decrypt = sm4.decrypt(userInfoStr);
                        String userStr = new String(decrypt);
                        JSONObject userObj = JSONObject.parseObject(userStr);
                        if (userObj.containsKey("phone")) {
                            phone = StrKit.str(userObj.get("phone"));
                        }
                        log.info("用户解密后信息:" + userStr);
                    } else {
                        // 否则返回错误信息
                        String msg = StrKit.str(jsonObject.get("msg"));
                        return ok("获取用户信息失败:" + msg);
                    }
                }
            }
            // 根据电话号码获取系统登录名
            String loginName = "";
            if (!"".equals(phone)) {
                List<V3xOrgMember> orgMemberList = orgManager.getMemberListWithOuterByMobile(phone, null);
                if (!orgMemberList.isEmpty()) {
                    loginName = orgMemberList.get(0).getLoginName();
                }
            } else {
                return ok("手机号未维护!");
            }
            // 构造并执行登录重定向
            if (!"".equals(loginName)) {
                long longUUID = UUIDLong.longUUID();
                String loginName_new = URLEncoder.encode(longUUID + "##" + loginName);
                response.sendRedirect("/seeyon/login/sso?from=dzddsso&ticketInfo=" + loginName_new + "&UserAgentFrom=pc");
            } else {
                return ok("手机号[" + phone + "]在系统中未匹配到对应的账号!");
            }

        } catch (Exception e) {
            log.error("单点登录接口异常信息:", e);
        }
        return null;
    }

    /**
     * 处理OA单点登录（SSO）请求
     * 该方法接收一个包含手机号的参数映射，尝试根据手机号获取对应的登录名，并生成一个重定向URL进行登录
     * 如果找不到匹配的登录名，或者在处理过程中遇到异常，则返回相应的错误信息
     *
     * @param param 包含手机号的参数映射
     * @return Response对象，包含重定向或错误信息
     */
    @GET
    @Path("oa/sso/phone")
    public Response oaSSOjgpt(Map<String, Object> param) {
        try {
            // 初始化登录名为空字符串
            String loginName = "";
            // 从参数中获取手机号并转换为字符串
            String phone = request.getParameter("phone");
            // 根据手机号获取组织成员列表
            List<V3xOrgMember> orgMemberList = orgManager.getMemberListWithOuterByMobile(phone, null);
            // 检查组织成员列表是否为空
            if (!orgMemberList.isEmpty()) {
                // 如果不为空，获取第一个组织成员的登录名
                loginName = orgMemberList.get(0).getLoginName();
            } else {
                // 如果为空，返回错误信息表示未找到匹配的账号
                return ok("手机号[" + phone + "]在系统中未匹配到对应的账号!");
            }
            // 检查登录名是否非空
            if (!"".equals(loginName)) {
                // 生成一个唯一的长UUID
                long longUUID = UUIDLong.longUUID();
                // 使用UUID和登录名生成新的登录名，并进行URL编码
                String loginName_new = URLEncoder.encode(longUUID + "##" + loginName);
                // 重定向到单点登录URL，并附带编码后的登录名作为票证信息
                response.sendRedirect("/seeyon/login/sso?from=dzddsso&ticketInfo=" + loginName_new + "&UserAgentFrom=pc");
            } else {
                // 如果登录名为空，返回错误信息表示未找到匹配的账号
                return ok("手机号[" + phone + "]在系统中未匹配到对应的账号!");
            }
        } catch (Exception e) {
            // 记录单点登录接口的异常信息
            log.error("单点登录接口异常信息:", e);
            // 返回异常信息
            return ok(e.getMessage());
        }
        // 如果执行到此处，表示已经成功重定向，返回null
        return null;
    }
}